package casbin_v2

import (
	"errors"
	"log"
	"strings"
	"time"

	. "gitee.com/tommickey/gose/v3/gose/gotconst"
	"gitee.com/tommickey/gose/v3/gose/gotgormv2"
	"gitee.com/tommickey/gose/v3/gose/gotviper"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"gorm.io/gorm"
)

var (
	// Enforcer casbin 全局操作指针
	Enforcer *casbin.SyncedEnforcer
)

func init() {
	// 9.casbin 依据配置文件设置参数(IsInit=1)初始化
	if gotviper.ConfigFile.GetInt("Casbin.IsInit") == 1 {
		var err error
		if Enforcer, err = InitCasbinEnforcer(); err != nil {
			log.Fatal(err.Error())
		}
	}
}

// InitCasbinEnforcer 创建 casbin Enforcer(执行器)
func InitCasbinEnforcer() (*casbin.SyncedEnforcer, error) {
	var tmpDbConn *gorm.DB
	var Enforcer *casbin.SyncedEnforcer
	switch strings.ToLower(gotviper.ConfigGormv2File.GetString("Gormv2.UseDbType")) {
	case "mysql":
		if gotgormv2.GormDbMysql == nil {
			return nil, errors.New(ErrorCasbinCanNotUseDbPtr)
		}
		tmpDbConn = gotgormv2.GormDbMysql
	case "sqlserver", "mssql":
		if gotgormv2.GormDbSqlserver == nil {
			return nil, errors.New(ErrorCasbinCanNotUseDbPtr)
		}
		tmpDbConn = gotgormv2.GormDbSqlserver
	case "postgre", "postgresql", "postgres":
		if gotgormv2.GormDbPostgreSql == nil {
			return nil, errors.New(ErrorCasbinCanNotUseDbPtr)
		}
		tmpDbConn = gotgormv2.GormDbPostgreSql
	default:
	}

	prefix := gotviper.ConfigFile.GetString("Casbin.TablePrefix")
	tbName := gotviper.ConfigFile.GetString("Casbin.TableName")

	a, err := gormadapter.NewAdapterByDBUseTableName(tmpDbConn, prefix, tbName)
	if err != nil {
		return nil, errors.New(ErrorCasbinCreateAdaptFail)
	}
	modelConfig := gotviper.ConfigFile.GetString("Casbin.ModelConfig")

	if m, err := model.NewModelFromString(modelConfig); err != nil {
		return nil, errors.New(ErrorCasbinNewModelFromStringFail + err.Error())
	} else {
		if Enforcer, err = casbin.NewSyncedEnforcer(m, a); err != nil {
			return nil, errors.New(ErrorCasbinCreateEnforcerFail)
		}
		_ = Enforcer.LoadPolicy()
		AutoLoad := gotviper.ConfigFile.GetDuration("Casbin.AutoLoadPolicySeconds")
		Enforcer.StartAutoLoadPolicy(time.Second * AutoLoad)
		return Enforcer, nil
	}
}
